//-------------------------------------------------------------
// \project PluginExample3
// \file ModuleRatioValueCorrect.java
// \brief 气候资料订正->比值订正法模块
// \author 王庆飞
// \date 2017-10-16
// \attention
// Copyright(c) 超图软件股份有限公司 气象事业部
// All Rights Reserved
// \version 1.0
//-------------------------------------------------------------

package com.mg.pluginexample3;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;

import com.mg.model.*;
import com.mg.pluginexample1.*;

public class ModuleRatioValueCorrect extends Module 
{
	public ModuleRatioValueCorrect(int nID) 
	{
		super(nID);
		
		m_alInputPort.add(new DataTablePort(this, Port.Type.CSV));
		m_alInputPort.add(new DataTablePort(this, Port.Type.CSV));
		
		m_alInputPort.get(0).SetName("例如：基本站1981-2016 月(旬)降水量");
		m_alInputPort.get(1).SetName("例如：考察站2008-2016 月(旬)降水量");
		
		m_alOutputPort.add(new Port(this, Port.Type.CSV));
		m_alOutputPort.get(0).SetName("例如：考察站多年(1981-2016)平均月(旬)降水量");
    }

	public String GetGroupName()
	{
		return "JDBC";
	}
	public String GetName()
	{
		return "比值订正法";
	}
	public String GetDescription()
	{
		return "用于订正降水量、日照时数。";
	}
	
	public boolean OnAttach(Port portFrom, Port portTo)
	{
		try
		{
			int i = FindPort(portFrom, false);
			if (i != -1)
				return true;
			i = FindPort(portTo, true);
			if (i == -1)
				return false;
			
			ArrayList<Param> alParam = new ArrayList<Param>();
			portFrom.GetModule().GetOutputParam(portFrom, alParam);
			if (alParam.size() != 1)
				return false;
			if (alParam.get(0).m_objValue != null && !(alParam.get(0).m_objValue instanceof List<?>))
				return false;
			portTo.SetType(portFrom.GetType());
			DataTablePort dtp = (DataTablePort)portTo;
			if (alParam.get(0).m_objValue instanceof List<?>)
				dtp.m_list = (List<String>)alParam.get(0).m_objValue;
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
			return false;
		}
		return true;
	}
	
	//用于 参数->XML 等
	public int GetParam(ArrayList<Param> alParam)
	{
		try
		{
			int nOffset = super.GetParam(alParam);
			//-------------------------------------------------------------------------------------------------------------------
		
        	
			Model.GetAlias(alParam, m_alAlias, nOffset);
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		
		return alParam.size();
	}
	//用于 XML->参数 等
	public int SetParam(final ArrayList<Param> alParam)
	{
		int i = super.SetParam(alParam);
		
		try
		{
			
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		return i;	
	}
	
	public boolean Execute()
	{
		try
		{
			int i = 0, j = 0, k = 0;
			
			DataTablePort dtp = (DataTablePort)m_alInputPort.get(0);
			boolean bTenDays = dtp.m_list.get(0).contains("旬");
			
			SimpleDateFormat sdf = new SimpleDateFormat(bTenDays ? "yyyy-MM-dd" : "yyyy-MM");
			m_alXData.clear();
			for (i = 2; i < dtp.m_list.size(); i++)
        	{
				String[] strs = dtp.m_list.get(i).split(",");
        		m_alXData.add(new XData(sdf.parse(strs[0]), Double.parseDouble(strs[1])));
        	}
			
			dtp = (DataTablePort)m_alInputPort.get(1);
			m_alYData.clear();
			for (i = 2; i < dtp.m_list.size(); i++)
        	{
				String[] strs = dtp.m_list.get(i).split(",");
        		m_alYData.add(new YData(sdf.parse(strs[0]), Double.parseDouble(strs[1])));
        	}
			
			//-------------------------------------------------------------------------------------------------------------------
			//统计同期各月(旬)值
			double[] x = new double[bTenDays ? 36 : 12], y = new double[bTenDays ? 36 : 12];
			int[] count = new int[bTenDays ? 36 : 12];
			for (i = 0; i < x.length; i++)
			{
				x[i] = 0.0;
				y[i] = 0.0;
				count[i] = 0;
			}
			k = 0;
			for (i = 0; i < m_alYData.size(); i++)
			{
				YData yd = m_alYData.get(i);
				if (yd.m_y < 0) //无效值
					continue;
				
				while (k < m_alXData.size() && m_alXData.get(k).m_dateTime.compareTo(yd.m_dateTime) < 0)
					++k;
				if (k == m_alXData.size())
					break;
				if (m_alXData.get(k).m_dateTime.compareTo(yd.m_dateTime) > 0)
					continue;
				if (m_alXData.get(k).m_x < 0) //无效值
					continue;
				
				Calendar c = new GregorianCalendar();
				c.setTime(yd.m_dateTime);
				if (bTenDays)
				{
					final int nDayOfMonth = c.get(Calendar.DAY_OF_MONTH);
					j = c.get(Calendar.MONTH) * 3 + (nDayOfMonth < 11 ? 0 : (nDayOfMonth < 21 ? 1 : 2));
				}
				else
				{
					j = c.get(Calendar.MONTH);
				}
				
				x[j] += m_alXData.get(k).m_x;
				y[j] += yd.m_y;
				++count[j];
			}
			//-------------------------------------------------------------------------------------------------------------------
			double sum_x = 0.0, sum_y = 0.0, b = 0.0;
			for (i = 0; i < x.length; i++)
			{
				if (count[i] != 0)
				{
					sum_x += (x[i] / count[i]);
					sum_y += (y[i] / count[i]);
				}
			}
			b = sum_y / sum_x; 
			//-------------------------------------------------------------------------------------------------------------------
			//统计基本站各月(旬)多年平均值
			for (i = 0; i < x.length; i++)
			{
				x[i] = 0.0;
				count[i] = 0;
			}
			for (i = 0; i < m_alXData.size(); i++)
			{
				XData xd = m_alXData.get(i);
				Calendar c = new GregorianCalendar();
				c.setTime(xd.m_dateTime);
				if (bTenDays)
				{
					final int nDayOfMonth = c.get(Calendar.DAY_OF_MONTH);
					j = c.get(Calendar.MONTH) * 3 + (nDayOfMonth < 11 ? 0 : (nDayOfMonth < 21 ? 1 : 2));
				}
				else
				{
					j = c.get(Calendar.MONTH);
				}
				
				x[j] += xd.m_x;
				++count[j];
			}
			for (i = 0; i < x.length; i++)
			{
				if (count[i] != 0)
					x[i] /= count[i];
			}
			//-------------------------------------------------------------------------------------------------------------------
			for (i = 0; i < x.length; i++)
				y[i] = x[i] * b;
			//-------------------------------------------------------------------------------------------------------------------
			m_llOutput.clear();
			m_llOutput.add((bTenDays ? "旬" : "月") + ",多年平均值");
			m_llOutput.add("TINYINT,FLOAT");
			for (i = 0; i < y.length; i++)
			{
				m_llOutput.add(String.format("%d,%f", i + 1, y[i])); 
			}
			
			OnParamChanged();
			return true;
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		catch (Error error)
		{
			error.printStackTrace();
		}
		
		return false;
	}
	
	public int GetOutputParam(Port port, ArrayList<Param> alParam)
	{
		int i = FindPort(port, false);
		if (i == -1)
			return 0;
		if (i == 0)
			alParam.add(new Param("CSV", m_llOutput));
		
		return alParam.size();
	}
	//---------------------------------------------------------------------------
	class XData //基本站数据
	{
		XData(Date dateTime, double x)
		{
			m_dateTime = dateTime;
			m_x = x;
		}
		
		Date m_dateTime;
		double m_x;
	}
	ArrayList<XData> m_alXData = new ArrayList<XData>();
	
	class YData //考察站数据
	{
		YData(Date dateTime, double y)
		{
			m_dateTime = dateTime;
			m_y = y;
		}
		
		Date m_dateTime;
		double m_y;
	}
	ArrayList<YData> m_alYData = new ArrayList<YData>();
	
	//---------------------------------------------------------------------------
	LinkedList<String> m_llOutput = new LinkedList<String>();
}
